﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Kokomo.Environment;
using System.Windows.Input;
using System.Diagnostics;
using Kokomo.Environment.Services;
using Kokomo.Environment.Commanding;

namespace Kokomo.Environment.Documents
{
	[ViewType(typeof(NavigationView))]
	public class NavigationDocumentViewModel : DocumentViewModel
	{
		public NavigationDocumentViewModel()
		{
			this.NavigationContext = new NavigationContext(new ParameterizedCommand(this.NavigateTo));
			this.BackStack = new Stack<object>();
			this.ForwardStack = new Stack<object>();
			this._goBackCommand = new DelegatedCommand(this.GoBack, this.CanGoBack);
			this._goForwardCommand = new DelegatedCommand(this.GoForward, this.CanGoForward);

			this._openNewViewCommand = new ParameterizedCommand((this.OpenNewView), this.CanOpenNewView);

			IImageProvider imageProvider = EnvironmentServices.DemandService<IImageProvider>();
			this.ObjectMenuItemViewModels = new MenuItemViewModel[] {
				new MenuViewModel(UiString.FromString(Messages.NavigationMenuTitle), new MenuItemViewModel[] {
					new MenuCommandItemViewModel(new CommandViewModel(
						this.GoBackCommand,
						UiString.FromString(Messages.GoBackMenuText),
						imageProvider.GetImage(StandardImageKeys.Back)
						)),
					new MenuCommandItemViewModel(new CommandViewModel(
						this.GoForwardCommand,
						UiString.FromString(Messages.GoForwardMenuText),
						imageProvider.GetImage(StandardImageKeys.Forward)
						))
				})
			};
		}

		public NavigationContext NavigationContext { get; private set; }
		public ICommand NavigateToCommand { get { return this.NavigationContext.NavigateToCommand; } }

		public void NavigateTo(object arg)
		{
			this.NavigateTo(arg, false);
		}
		public void NavigateTo(object arg, bool ignoreKeyGestures)
		{
			if (arg == null) return;

			if (
				!ignoreKeyGestures
				&& Keyboard.Modifiers.HasFlag(ModifierKeys.Shift)
				)
			{
				this.OpenNewView(arg);
			}
			else
			{
				DetailViewModel detail = arg as DetailViewModel;
				if (detail == null)
					detail = this.GetDetailViewModelFor(arg, this.NavigationContext);

				if (detail != null)
				{
					if (
						(this._currentDetailViewModel != null)
						&& (this._currentDetailViewModel != detail)
						&& (!this.IsNavigating)
						)
					{
						if (this.CurrentDetailViewModel != null)
						{
							//object target = this.CurrentDetailViewModel.Object;
							object target = this.CurrentDetailViewModel;
							this.BackStack.Push(target);
						}
						this.ForwardStack.Clear();
					}

					this.CurrentDetailViewModel = detail;
				}
			}
		}
		protected virtual bool IsViewModel(object obj)
		{
			return (obj is DetailViewModel);
		}
		protected virtual DetailViewModel GetDetailViewModelFor(object obj, NavigationContext navigationContext)
		{
			DetailViewModel detail = obj as DetailViewModel;
			return detail;
		}

		#region Navigation

		protected Stack<object> BackStack { get; private set; }
		protected Stack<object> ForwardStack { get; private set; }

		public bool IsNavigating { get; private set; }

		private DelegatedCommand _goBackCommand;
		public ICommand GoBackCommand { get { return this._goBackCommand; } }
		private bool CanGoBack()
		{
			return this.BackStack.Count > 0;
		}
		private void GoBack()
		{
			if (!this.CanGoBack()) return;

			this.IsNavigating = true;
			try
			{

				if (this.CurrentDetailViewModel != null)
				{
					object target;
					//target = this.CurrentDetailViewModel.Object;
					target = this.CurrentDetailViewModel;

					this.ForwardStack.Push(target);
				}
				this.NavigateTo((this.BackStack.Pop()));
			}
			finally
			{
				this.IsNavigating = false;
			}
		}

		private DelegatedCommand _goForwardCommand;
		public ICommand GoForwardCommand { get { return this._goForwardCommand; } }
		private bool CanGoForward()
		{
			return this.ForwardStack.Count > 0;
		}
		private void GoForward()
		{
			if (!this.CanGoForward()) return;

			this.IsNavigating = true;
			try
			{
				if (this.CurrentDetailViewModel != null)
				{
					//object target = this.CurrentDetailViewModel.Object;
					object target = this.CurrentDetailViewModel;
					this.BackStack.Push(target);
				}
				this.NavigateTo(this.ForwardStack.Pop());
			}
			finally
			{
				this.IsNavigating = false;
			}
		}

		private ParameterizedCommand _openNewViewCommand;
		public ICommand OpenNewViewCommand { get { return this._openNewViewCommand; } }
		private bool CanOpenNewView(object arg)
		{
			return (arg != null) || (this._currentDetailViewModel != null);
		}
		protected virtual void OpenNewView(object arg)
		{
			if (arg == null)
			{
				if (this._currentDetailViewModel != null)
					arg = this._currentDetailViewModel.Content;
			}
			if (arg == null) return;

			DetailSurrogateViewModel surrogate = new DetailSurrogateViewModel(this.GetDetailViewModelFor);
			surrogate.NavigateTo(arg, true);
			surrogate.IsFloating = this.IsFloating;
			surrogate.HelpMenuItemViewModels = this.HelpMenuItemViewModels;
			EnvironmentServices.DocumentManager.ShowDocument(surrogate);
		}
		#endregion

		#region Details
		private DetailViewModel _currentDetailViewModel;
		public DetailViewModel CurrentDetailViewModel
		{
			get { return this._currentDetailViewModel; }
			set
			{
				this._currentDetailViewModel = value;
				this.OnCurrentDetailViewModelChanged();
			}
		}
		protected virtual void OnCurrentDetailViewModelChanged()
		{
			this._goBackCommand.OnCanExecuteChanged();
			this._goForwardCommand.OnCanExecuteChanged();
			this._openNewViewCommand.OnCanExecuteChanged();
			CommandManager.InvalidateRequerySuggested();

			this.OnPropertyChanged("CurrentDetailViewModel");
		}

		//public ViewSettings ViewSettings
		//{
		//    get { return AssemblyAnalyzerEditor.ViewSettings; }
		//}
		#endregion
	}
}
